package controller

import (
	"encoding/base64"
	"errors"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	uuid "github.com/satori/go.uuid"
	"github.com/skip2/go-qrcode"
	"go-im-server-demo/src/utils"
	jwtu "go-im-server-demo/src/utils/jwt"
	"net/http"
	"time"
)

const (
	QRCODE_STATUS_UNSCAN       = 0 // 未扫码
	QRCODE_STATUS_CODE_INVALID = 1 // 二维码已失效
	QRCODE_STATUS_SCANED       = 2 // 已扫码状态
	QRCODE_STATUS_CANCEL       = 3 // 用户取消扫码
	QRCODE_STATUS_CONFIRM      = 4 // 用户确认扫码登陆

)

type QrCodeContext struct {
	ExpTime   int64
	Status    int
	ChannelId string
	Token     string
}

type QrcodeManager map[string]*QrCodeContext

var (
	qrManager QrcodeManager = QrcodeManager{}
)

func QrCode(ctx *gin.Context) {
	channelId := uuid.NewV4().String()
	json := map[string]interface{}{
		"channelId": channelId,
	}
	s, _ := utils.StructToJson(json)
	qr, err := qrcode.New("login:="+s, qrcode.Medium)
	if err != nil {
		panic(err)
	}

	qrc := &QrCodeContext{
		ExpTime:   time.Now().Add(time.Minute * 5).Unix(),
		Status:    QRCODE_STATUS_UNSCAN,
		ChannelId: channelId,
	}
	qrManager[channelId] = qrc

	writer := &utils.ByteArrayToWriter{}
	err = qr.Write(150, writer)
	if err != nil {
		panic(err)
	}
	base64Str := base64.StdEncoding.EncodeToString(writer.ByteArray)

	ctx.JSON(http.StatusOK, gin.H{
		"code":      "200",
		"data":      base64Str,
		"channelId": channelId,
	})

}
func VaildScanCode(ctx *gin.Context) {

	var m map[string]interface{}
	err := ctx.BindJSON(&m)
	if err != nil {
		panic(err)
	}

	channelId := m["channelId"].(string)
	qrc, ok := qrManager[channelId]

	if !ok || qrc.Status == QRCODE_STATUS_CODE_INVALID {
		ctx.JSON(http.StatusOK, gin.H{
			"code":   "200",
			"status": 1,
		})

		if qrc.Status == QRCODE_STATUS_CODE_INVALID {
			delete(qrManager, channelId)
		}
		return
	}

	ctx.JSON(http.StatusOK, gin.H{
		"code":   "200",
		"status": qrc.Status,
		"token":  qrc.Token,
	})

}
func ScanCode(ctx *gin.Context) {
	var m map[string]interface{}
	err := ctx.BindJSON(&m)
	if err != nil {
		panic(err)
	}

	channelId := m["channelId"].(string)
	qrc, ok := qrManager[channelId]
	if !ok {
		ctx.JSON(http.StatusOK, gin.H{
			"code": "500",
			"msg":  "二维码无效",
		})
		return
	}
	if qrc.ExpTime >= time.Now().Unix() {
		qrc.Status = QRCODE_STATUS_SCANED
		ctx.JSON(http.StatusOK, gin.H{
			"code": "200",
			"msg":  "已设置扫码状态",
		})
	} else {
		qrc.Status = QRCODE_STATUS_CODE_INVALID
		ctx.JSON(http.StatusOK, gin.H{
			"code": "500",
			"msg":  "二维码已过期",
		})
	}
}

func Confim(ctx *gin.Context) {

	var m map[string]interface{}
	err := ctx.BindJSON(&m)
	if err != nil {
		panic(err)
	}

	channelId := m["channelId"].(string)
	qrc, ok := qrManager[channelId]
	if !ok {
		ctx.JSON(http.StatusOK, gin.H{
			"code": "500",
			"msg":  "二维码无效",
		})
		return
	}

	accept := m["accept"].(bool)
	if !accept {
		qrc.Status = QRCODE_STATUS_CANCEL
		ctx.JSON(http.StatusOK, gin.H{
			"code": "200",
			"data": "0",
			"msg":  "取消扫码登录",
		})
		return
	} else {
		qrc.Status = QRCODE_STATUS_CONFIRM
		token := ctx.GetHeader("token")

		jwtHelper := jwtu.Default()
		c, err := jwtHelper.Verify(token)
		if err != nil {
			fmt.Println(err)
			panic(errors.New("TOKEN验证失败"))
		}
		mapClaims := c.(jwt.MapClaims)
		err = mapClaims.Valid()
		if err != nil {
			fmt.Println(err)
			panic(errors.New("TOKEN验证失败"))
		}

		uid := mapClaims["uid"].(string)

		token, err = jwtHelper.Sign(jwt.MapClaims{
			"uid": uid,
		}, time.Hour*24*7)

		if err != nil {
			panic(err)
		}
		qrc.Token = token
	}

	ctx.JSON(http.StatusOK, gin.H{
		"code": "200",
		"data": "1",
		"msg":  "确认扫码完成",
	})

}
